package com.angcyo.javafx.ui

import com.angcyo.core.component.file.writeTo
import com.angcyo.javafx.base.ex.getImageFx
import com.angcyo.javafx.base.ex.onDelay
import com.angcyo.log.L
import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.event.ActionEvent
import javafx.geometry.Insets
import javafx.scene.Node
import javafx.scene.control.*
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.input.*
import javafx.scene.layout.*
import javafx.scene.paint.Color
import javafx.scene.paint.Paint
import java.io.File

/**
 * Email:angcyo@126.com
 * @author angcyo
 * @date 2020/12/30
 */

/**根据[Tab]的名字, 切换tab*/
fun TabPane?.switchByName(targetTabName: String) {
    this?.tabs?.forEachIndexed { index, tab ->
        if (tab.text == targetTabName) {
            selectionModel?.select(index)
        }
    }
}

fun TabPane?.removeTabByName(targetTabName: String): Tab? {
    return this?.tabs?.find { tab -> tab.text == targetTabName }?.apply {
        tabs?.remove(this)
    }
}

/**根据[Tab]的ID, 切换tab*/
fun TabPane?.switchById(targetTabId: String) {
    this?.tabs?.forEachIndexed { index, tab ->
        if (tab.id == targetTabId) {
            selectionModel?.select(index)
        }
    }
}

fun TabPane?.removeTabById(targetTabId: String): Tab? {
    return this?.tabs?.find { tab -> tab.id == targetTabId }?.apply {
        tabs?.remove(this)
    }
}

/**通过资源名称, 设置[ImageView]显示的图片
 * https://blog.csdn.net/MAIMIHO/article/details/106367255
 * */
fun ImageView.setImageResource(resImage: String) {
    image = getImageFx(resImage)
}

fun ImageView.setImageUrl(url: String) {
    image = Image(url)
}

fun ImageView.setImageFile(path: String) {
    image = Image("file:$path")
}

fun TextInputControl.setInputText(text: String?, lastCaret: Boolean = true) {
    this.text = text
    if (lastCaret) {
        this.positionCaret(text?.length ?: 0)
    }
}

/**[filePath]文件全路径*/
fun TextInputControl.saveOnTextChanged(filePath: String, append: Boolean = false) {
    saveOnTextChanged(File(filePath), append)
}

/**当文本改变时, 保存到文件[file]*/
fun TextInputControl?.saveOnTextChanged(file: File, append: Boolean = false) {
    this?.textProperty()?.addListener { observable, oldValue, newValue ->
        newValue?.writeTo(file, append)
    }
}

/**监听文本改变*/
fun TextInputControl?.onTextChanged(action: (observable: ObservableValue<out String>?, oldValue: String?, newValue: String?) -> Unit) {
    this?.textProperty()?.addListener { observable, oldValue, newValue ->
        action(observable, oldValue, newValue)
    }
}

/**过滤输入的文本*/
fun TextInputControl.filterText(pattern: String = "\\d*") {
    textProperty().addListener { observable, oldValue, newValue ->
        if (!newValue.matches(pattern.toRegex())) {
            text = oldValue
        }
    }
}

fun ComboBoxBase<String>?.onTextChanged(action: (observable: ObservableValue<out String>?, oldValue: String?, newValue: String?) -> Unit) {
    this?.valueProperty()?.addListener { observable, oldValue, newValue ->
        action(observable, oldValue, newValue)
    }
}

/**是否要激活[Node]*/
fun Node?.enable(enable: Boolean = true): Boolean {
    if (this == null) {
        return false
    }
    isDisable = !enable
    return !isDisable
}

/**元素可见*/
fun Node?.visible(visible: Boolean = true): Boolean {
    if (this == null) {
        return false
    }
    isVisible = visible
    isManaged = visible
    return isVisible
}

/**不可见*/
fun Region?.invisible(invisible: Boolean = true) {
    if (this == null) {
        return
    }
    prefHeight = if (invisible) {
        0.0
    } else {
        Region.USE_COMPUTED_SIZE
    }
}

/**大小改变*/
fun Region.onSizeChanged(action: (width: Number, height: Number) -> Unit) {
    widthProperty().addListener { observable, oldValue, newValue ->
        action(newValue, height)
    }
    heightProperty().addListener { observable, oldValue, newValue ->
        action(width, newValue)
    }
}

/**鼠标双击回调*/
fun Node?.setOnMouseDoubleClicked(delay: Long = 300, action: (MouseEvent) -> Unit) {
    this?.apply {
        onMouseClicked = DoubleWrapEventHandler(onMouseClicked, delay, action)
    }
}

/**背景*/
fun background(color: Paint, radii: CornerRadii = CornerRadii.EMPTY, insets: Insets = Insets.EMPTY): Background {
    return Background(BackgroundFill(color, radii, insets))
}

fun <T> ObservableList<T>.reset(action: ObservableList<T>.() -> Unit) {
    clear()
    action()
}

/**匹配按键
 * [Ctrl+S] it.match(KeyCode.S, KeyCodeCombination.CONTROL_DOWN)
 * */
fun KeyEvent.match(code: KeyCode, vararg modifier: KeyCombination.Modifier): Boolean {
    val combination = KeyCodeCombination(code, *modifier)
    return combination.match(this)
}

fun <T> List<T>?.toObservableList(): ObservableList<T> = FXCollections.observableList(this ?: emptyList())

/**重新设置[ListView]显示的数据*/
fun <T> ListView<T>?.resetItemList(
    itemList: List<T>?,
    selectItem: T? = this?.selectionModel?.selectedItem ?: itemList?.firstOrNull()
) {
    this?.apply {
        items?.reset {
            addAll(itemList.toObservableList())
        }
        //恢复选中
        selectItem?.let { selectionModel.select(it) }
    }
}

fun <T> ComboBox<T>?.resetItemList(
    itemList: List<T>?,
    selectItem: T? = this?.selectionModel?.selectedItem ?: itemList?.firstOrNull()
) {
    this?.apply {
        items?.reset {
            addAll(itemList.toObservableList())
        }
        //恢复选中
        selectItem?.let { selectionModel.select(it) }
    }
}

fun <T> ChoiceBox<T>?.resetItemList(
    itemList: List<T>?,
    selectItem: T? = this?.selectionModel?.selectedItem ?: itemList?.firstOrNull()
) {
    this?.apply {
        items?.reset {
            addAll(itemList.toObservableList())
        }
        //恢复选中
        selectItem?.let { selectionModel.select(it) }
    }
}

fun Pane.resetChildren(childList: Collection<Node>?) {
    children?.reset {
        addAll(childList ?: emptyList())
    }
}

/**列表选中改变之后*/
fun <T> ListView<T>.onSelectedChanged(action: (oldIndex: Number, newIndex: Number) -> Unit): ObservableValue<out Number>? {
    var result: ObservableValue<out Number>? = null
    //列表选择
    selectionModel?.selectedIndexProperty()?.addListener { observable, oldValue, newValue ->
        result = observable
        action(oldValue, newValue)
    }
    return result
}

/**列表选中监听*/
fun <T> ListView<T>.onSelectedItem(action: (selectedIndex: Number, selectedItem: T) -> Unit): ObservableValue<out T>? {
    var result: ObservableValue<out T>? = null

    this.apply {
        var selectedItem: T? = null
        selectionModel?.selectedIndexProperty()?.addListener { observable, oldValue, newValue ->
            //后回调
            L.i("selected:[$newValue] [$selectedItem]")
            selectedItem?.let {
                action(newValue, it)
            }
        }
        selectionModel?.selectedItemProperty()?.addListener { observable, oldValue, newValue ->
            //先回调
            //L.i("2...$newValue")
            result = observable
            selectedItem = newValue
        }
    }
    return result
}

/**[TabPane]选中监听*/
fun TabPane.onSelectedItem(action: (selectedIndex: Number, selectedItem: Tab) -> Unit): ObservableValue<out Tab>? {
    var result: ObservableValue<out Tab>? = null

    this.apply {
        selectionModel?.selectedIndexProperty()?.addListener { observable, oldValue, newValue ->
            //先回调
            L.i("selected:[$newValue]")
        }
        selectionModel?.selectedItemProperty()?.addListener { observable, oldValue, newValue ->
            //后回调
            //L.i("2...$newValue")
            result = observable
            action(selectionModel.selectedIndex, newValue)
        }
    }
    return result
}

fun String.toColor(): Color = Color.valueOf(this)

fun Control.tooltip(tip: String) {
    tooltip = Tooltip(tip)
}

/**[later]后, 激活按钮*/
fun Node.enableOnLater(later: Long = 1000) {
    enable(false)
    onDelay(later) {
        enable(true)
    }
}

/**触发点击事件*/
fun ButtonBase.clickAction() {
    onAction?.handle(ActionEvent())
}